@file:UseSerializers(ResourceLocationSerializer::class, ItemStackSerializer::class)

package com.lalameow.researchstation.network

import com.lalameow.researchstation.Cbor
import com.lalameow.researchstation.Identifiers
import com.lalameow.researchstation.ResearchStation
import com.lalameow.researchstation.api.technology.TechnologyCategories
import com.lalameow.researchstation.api.technology.TechnologyCategory
import com.lalameow.researchstation.researching.ResearchingTree
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
import net.fabricmc.api.EnvType
import net.fabricmc.api.Environment
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
import net.silkmc.silk.core.serialization.serializers.ResourceLocationSerializer
import net.silkmc.silk.nbt.serialization.serializer.ItemStackSerializer
import net.silkmc.silk.network.packet.c2sPacket
import net.silkmc.silk.network.packet.s2cPacket

@OptIn(ExperimentalSerializationApi::class)
internal object ResearchingTreeNetwork {
    val responsePacket = s2cPacket<Packet>(Identifiers.RESEARCHING_TREE, ResearchStation.Cbor)
    val requestPacket = c2sPacket<Identifier>(Identifiers.RESEARCHING_TREE, ResearchStation.Cbor)

    private val map = mutableMapOf<Identifier, ResearchingTree>()

    @Environment(EnvType.CLIENT)
    private val mutableCategories = MutableSharedFlow<Map<Identifier, ResearchingTree>>()

    @Environment(EnvType.CLIENT)
    val categories: SharedFlow<Map<Identifier, ResearchingTree>> = mutableCategories

    init {
        requestPacket.receiveOnServer { data, context ->
            responsePacket.send(
                Packet(requireNotNull(TechnologyCategories[data]) { "Technology category can't find" }, context.player),
                context.player
            )
        }
        responsePacket.receiveOnClient { packet, context ->
            map[packet.id] = packet.tree
            mutableCategories.emit(map)
        }
    }

    @Serializable
    internal data class Packet(
        val id: Identifier,
        val tree: ResearchingTree = ResearchingTree()
    ) {
        constructor(category: TechnologyCategory, context: ServerPlayerEntity) : this(
            category.id,
            ResearchingTree(category.technologies, context)
        )
    }
}
